/*
	Commands execution unit for loader.  Handles:
	-	 Command registration
	-	 Command execution through submodule interface
	-	 CSE console command parsing & execution
*/
#include "Loader/commands.h"
#include "obse/CommandTable.h"
#include "obse/ParamInfos.h"
#include "Loader/aresParamInfos.h"

// Include the OBSE version of TESObjectREFR for use in processing arguments
// We cannot use the COEF version because 
// (1) the loader doesn't import it's member functions
// (2) it would collide with the OBSE version, which is forcibly included by PluginAPI.h
// The second issue will be fixed in a future version of OBSE, so we may be 
// able to use COEF classes here in a limited capacity at some later date.
#include "obse/GameObjects.h"   

/*--------------------------------------------------------------------------------------------*/
// Ported from CommandTable.cpp so we don't have to include the entire file
bool Cmd_Default_Execute(COMMAND_ARGS) {return true;} // nop command handler for script editor
bool Cmd_Default_Eval(COMMAND_ARGS_EVAL) {return true;} // nop command evaluator for script editor

/*--------------------------------------------------------------------------------------------*/
// Convenient (albeit disgusting) macros for defining commands
#define DEFINE_CMD_GET(type, cmnd, alias, retn, desc) \
	bool Cmd_Get ## type ## cmnd ## _Execute(COMMAND_ARGS) { \
		*result = 0; \
		TESForm* form = 0; \
		g_scriptIntfc->ExtractArgsEx(paramInfo, arg1, opcodeOffsetPtr, scriptObj, eventList, &form); \
		if (form && (thisObj = OBLIVION_CAST(form,TESForm,TESObjectREFR))) form = 0; \
		if (!form && thisObj) form = thisObj->GetBaseForm(); \
		*result = (SInt32)g_submoduleInfc->Get ## type ## cmnd ## (form); \
		return true; \
	} \
	DEFINE_CMD_PLUGIN_ALT(Get ## type ## cmnd, Get ## alias, desc, 0, kParams_OneInventoryObject)

#define DEFINE_CMD_SET(type, cmnd, alias, vtype, desc) \
	bool Cmd_Set ## type ## cmnd ## _Execute(COMMAND_ARGS) { \
		*result = 0; \
		TESForm* form = 0; \
		vtype val = 0; \
		g_scriptIntfc->ExtractArgsEx(paramInfo, arg1, opcodeOffsetPtr, scriptObj, eventList, &val, &form); \
		if (form && (thisObj = OBLIVION_CAST(form,TESForm,TESObjectREFR))) form = 0; \
		if (!form && thisObj) form = thisObj->GetBaseForm(); \
		*result = g_submoduleInfc->Set ## type ## cmnd ## (form, val)?1:0; \
		return true; \
	} \
	DEFINE_CMD_PLUGIN_ALT(Set ## type ## cmnd, Set ## alias, desc, 0, kParams_OneInt_OneInventoryObject)

#define DEFINE_CMD_PAIR(type, cmnd, alias, retval, desc) \
	DEFINE_CMD_GET(type, cmnd, alias, retval, "Gets " desc) \
	DEFINE_CMD_SET(type, cmnd, alias, retval, "Sets " desc)

#define DEFINE_CMD_GET_STR(type, cmnd, alias, desc) \
	bool Cmd_Get ## type ## cmnd ## _Execute(COMMAND_ARGS) { \
		*result = 0; \
		TESForm* form = 0; \
		g_scriptIntfc->ExtractArgsEx(paramInfo, arg1, opcodeOffsetPtr, scriptObj, eventList, &form); \
		if (form && (thisObj = OBLIVION_CAST(form,TESForm,TESObjectREFR))) form = 0; \
		if (!form && thisObj) form = thisObj->GetBaseForm(); \
		std::string str = g_submoduleInfc->Get ## type ## cmnd ## (form); \
		*result = g_stringIntfc->CreateString(str.c_str(), scriptObj); \
		return true; \
	} \
	DEFINE_CMD_PLUGIN_ALT(Get ## type ## cmnd, Get ## alias, desc, 0, kParams_OneInventoryObject)

#define DEFINE_CMD_SET_STR(type, cmnd, alias, desc) \
	bool Cmd_Set ## type ## cmnd ## _Execute(COMMAND_ARGS) { \
		*result = 0; \
		TESForm* form = 0; \
		char val[0x200] = {{0}}; \
		g_scriptIntfc->ExtractArgsEx(paramInfo, arg1, opcodeOffsetPtr, scriptObj, eventList, &val, &form); \
		if (form && (thisObj = OBLIVION_CAST(form,TESForm,TESObjectREFR))) form = 0; \
		if (!form && thisObj) form = thisObj->GetBaseForm(); \
		*result = g_submoduleInfc->Set ## type ## cmnd ## (form, val)?1:0; \
		return true; \
	} \
	DEFINE_CMD_PLUGIN_ALT(Set ## type ## cmnd, Set ## alias, desc, 0, kParams_OneString_OneInventoryObject)

#define DEFINE_CMD_PAIR_STR(type, cmnd, alias, desc) \
	DEFINE_CMD_GET_STR(type, cmnd, alias, "Gets " desc) \
	DEFINE_CMD_SET_STR(type, cmnd, alias, "Sets " desc)

/*--------------------------------------------------------------------------------------------*/
// Convenient macros for registering commands
#define REGISTER_CMD(cmnd) \
	g_obseIntfc->RegisterCommand(&kCommandInfo_ ## cmnd ## )

#define REGISTER_CMD_GET(type, cmnd) \
	REGISTER_CMD(Get ## type ## cmnd ## )

#define REGISTER_CMD_SET(type, cmnd) \
	REGISTER_CMD(Set ## type ## cmnd ## )

#define REGISTER_CMD_PAIR(type, cmnd) \
	REGISTER_CMD_GET(type, cmnd); \
	REGISTER_CMD_SET(type, cmnd)

#define REGISTER_CMD_FORM(cmnd) \
	g_obseIntfc->RegisterTypedCommand(&kCommandInfo_ ## cmnd ## , kRetnType_Form)

#define REGISTER_CMD_GET_FORM(type, cmnd) \
	REGISTER_CMD_FORM(Get ## type ## cmnd ## )

#define REGISTER_CMD_SET_FORM(type, cmnd) \
	REGISTER_CMD_FORM(Set ## type ## cmnd ## )

#define REGISTER_CMD_PAIR_FORM(type, cmnd) \
	REGISTER_CMD_GET_FORM(type, cmnd); \
	REGISTER_CMD_SET_FORM(type, cmnd)

#define REGISTER_CMD_STR(cmnd) \
	g_obseIntfc->RegisterTypedCommand(&kCommandInfo_ ## cmnd ## , kRetnType_String)

#define REGISTER_CMD_GET_STR(type, cmnd) \
	REGISTER_CMD_STR(Get ## type ## cmnd)

#define REGISTER_CMD_PAIR_STR(type, cmnd) \
	REGISTER_CMD_GET_STR(type, cmnd); \
	REGISTER_CMD_SET(type, cmnd)

/*--------------------------------------------------------------------------------------------*/
// New script commands for ARES
bool Cmd_ListMyForms_Execute(COMMAND_ARGS)
{
	/*
		Execution function for ListMyForms
		This method requires the use of some both COEF-specific code (the ExtendedForm component)
		and a static variable of the MyForm class.  These are not available in the loader project.
		Therefore, to proceed with this command, execution has to be transferred to the Submodule.
		This is done with the Submodule Interface - see below.
	*/
	*result = 0; // initialize result
	g_submoduleInfc->ListMyForms(); // invoke the ListMyForms() method of the submodule interface to hand off execution
	return true;
}
DEFINE_COMMAND_PLUGIN(ListMyForms, "Lists all MagicItemGenerator in the extended data handler", 0, 1, kParams_OneOptionalInventoryObject)

DEFINE_CMD_PAIR		(MagicItemGenerator,IsSuffix,		MIGisSuf,	bool,	"whether or not the MagicItemGenerator's affixes are suffixes.")
DEFINE_CMD_PAIR		(MagicItemGenerator,MinUses,		MIGminUses,	UInt16,	"the minimum uses of the generated MagicItem.")
DEFINE_CMD_PAIR		(MagicItemGenerator,MaxUses,		MIGmaxUses,	UInt16,	"the maximum uses of the generated MagicItem.")
DEFINE_CMD_PAIR		(MagicItemGenerator,Rank,			MIGrank,	SInt16,	"the MagicItemGenerator's rank."			)
DEFINE_CMD_PAIR		(MagicItemGenerator,Frequency,		MIGfreq,	UInt8,	"the MagicItemGenerator's frequency."		)
DEFINE_CMD_PAIR		(MagicItemGenerator,IsAutocalc,		MIGisAuto,	bool,	"whether or not the generated MagicItem is autocalc'd.")
DEFINE_CMD_GET		(MagicItemGenerator,AffixMask,		MIGmask,	UInt8,	"the MagicItemGenerator's affix mask."		)
DEFINE_CMD_PAIR_STR	(MagicItemGenerator,AffixSubpetty,	MIGsub,				"the MagicItemGenerator's Subpetty affix."	)
DEFINE_CMD_PAIR_STR	(MagicItemGenerator,AffixPetty,		MIGpet,				"the MagicItemGenerator's Petty affix."		)
DEFINE_CMD_PAIR_STR	(MagicItemGenerator,AffixLesser,	MIGles,				"the MagicItemGenerator's Lesser affix."	)
DEFINE_CMD_PAIR_STR	(MagicItemGenerator,AffixCommon,	MIGcom,				"the MagicItemGenerator's Common affix."	)
DEFINE_CMD_PAIR_STR	(MagicItemGenerator,AffixGreater,	MIGgrt,				"the MagicItemGenerator's Greater affix."	)
DEFINE_CMD_PAIR_STR	(MagicItemGenerator,AffixGrand,		MIGgnd,				"the MagicItemGenerator's Grand affix."		)
DEFINE_CMD_PAIR_STR	(MagicItemGenerator,AffixUltragrand,MIGult,				"the MagicItemGenerator's Ultragrand affix.")
DEFINE_CMD_PAIR_STR	(MagicItemGenerator,AffixNegative,	MIGneg,				"the MagicItemGenerator's Negative affix."	)
	
DEFINE_CMD_PAIR_STR	(AffixFilter,		NameFilter,		AFltName,			"the AffixFilter's name filter."			)
DEFINE_CMD_PAIR		(AffixFilter,		MinValue,		AFltMinVal,	double,	"the AffixFilter's minimum value."			)
DEFINE_CMD_PAIR		(AffixFilter,		MaxValue,		AFltMaxVal,	double,	"the AffixFilter's maximum value."			)
DEFINE_CMD_PAIR		(AffixFilter,		MinWeight,		AFltMinWht,	double,	"the AffixFilter's minimum weight."			)
DEFINE_CMD_PAIR		(AffixFilter,		MaxWeight,		AFltMaxWht,	double,	"the AffixFilter's maximum weight."			)
DEFINE_CMD_PAIR		(AffixFilter,		MinDurability,	AFltMinDur,	double,	"the AffixFilter's minimum durability."		)
DEFINE_CMD_PAIR		(AffixFilter,		MaxDurability,	AFltMaxDur,	double,	"the AffixFilter's maximum durability."		)

DEFINE_CMD_PAIR		(AffixFilter,		ApparelMask,	AFltApp,	UInt8,	"the AffixFilter's apparel mask."			)
DEFINE_CMD_PAIR		(AffixFilter,		MinArmorRating,	AFltMinAR,	double,	"the AffixFilter's minimum armor rating."	)
DEFINE_CMD_PAIR		(AffixFilter,		MaxArmorRating,	AFltMaxAR,	double,	"the AffixFilter's maximum armor rating."	)
DEFINE_CMD_PAIR		(AffixFilter,		HidesRings,		AFltHidRing,int,	"the AffixFilter requires hide rings."		)
DEFINE_CMD_PAIR		(AffixFilter,		HidesAmulet,	AFltHidAmmy,int,	"the AffixFilter requires hide amulet."		)
DEFINE_CMD_PAIR		(AffixFilter,		BipedHead,		AFltHead,	int,	"the AffixFilter requires the head biped slot.")
DEFINE_CMD_PAIR		(AffixFilter,		BipedHair,		AFltHair,	int,	"the AffixFilter requires the hair biped slot.")
DEFINE_CMD_PAIR		(AffixFilter,		BipedBodyLower,	AFltBodyLo,	int,	"the AffixFilter requires the lower body biped slot.")
DEFINE_CMD_PAIR		(AffixFilter,		BipedBodyUpper,	AFltBodyUp,	int,	"the AffixFilter requires the upper body biped slot.")
DEFINE_CMD_PAIR		(AffixFilter,		BipedHand,		AFltHand,	int,	"the AffixFilter requires the hand biped slot.")
DEFINE_CMD_PAIR		(AffixFilter,		BipedFoot,		AFltFoot,	int,	"the AffixFilter requires the foot biped slot.")
DEFINE_CMD_PAIR		(AffixFilter,		BipedRingLeft,	AFltRingL,	int,	"the AffixFilter requires the left ring biped slot.")
DEFINE_CMD_PAIR		(AffixFilter,		BipedRingRight,	AFltRingR,	int,	"the AffixFilter requires the right ring biped slot.")
DEFINE_CMD_PAIR		(AffixFilter,		BipedAmulet,	AFltAmmy,	int,	"the AffixFilter requires the amulet biped slot.")
DEFINE_CMD_PAIR		(AffixFilter,		BipedWeapon,	AFltWep,	int,	"the AffixFilter requires the weapon biped slot.")
DEFINE_CMD_PAIR		(AffixFilter,		BipedWeaponBack,AFltWepB,	int,	"the AffixFilter requires the back weapon biped slot.")
DEFINE_CMD_PAIR		(AffixFilter,		BipedWeaponSide,AFltWepS,	int,	"the AffixFilter requires the side weapon biped slot.")
DEFINE_CMD_PAIR		(AffixFilter,		BipedQuiver,	AFltQuiv,	int,	"the AffixFilter requires the quiver biped slot.")
DEFINE_CMD_PAIR		(AffixFilter,		BipedShield,	AFltShld,	int,	"the AffixFilter requires the shield biped slot.")
DEFINE_CMD_PAIR		(AffixFilter,		BipedTorch,		AFltTrch,	int,	"the AffixFilter requires the torch biped slot.")
DEFINE_CMD_PAIR		(AffixFilter,		BipedTail,		AFltTail,	int,	"the AffixFilter requires the tail biped slot.")
DEFINE_CMD_PAIR_STR	(AffixFilter,		ModelFilterBipedMale,	AFltBipM,	"the AffixFilter's male biped model filter.")
DEFINE_CMD_PAIR_STR	(AffixFilter,		ModelFilterBipedFemale,	AFltBipF,	"the AffixFilter's female biped model filter.")
DEFINE_CMD_PAIR_STR	(AffixFilter,		ModelFilterGroundMale,	AFltGndM,	"the AffixFilter's male ground model filter.")
DEFINE_CMD_PAIR_STR	(AffixFilter,		ModelFilterGroundFemale,AFltGndF,	"the AffixFilter's female ground model filter.")
DEFINE_CMD_PAIR_STR	(AffixFilter,		IconFilterMale,			AFltIcoM,	"the AffixFilter's male icon filter."		)
DEFINE_CMD_PAIR_STR	(AffixFilter,		IconFilterFemale,		AFltIcoF,	"the AffixFilter's female icon filter."		)
	
DEFINE_CMD_PAIR		(AffixFilter,		WeaponMask,		AFltWep,	UInt8,	"the AffixFilter's weapon mask."			)
DEFINE_CMD_PAIR		(AffixFilter,		MinDamage,		AFltMinDmg,	double,	"the AffixFilter's minimum attack damage."	)
DEFINE_CMD_PAIR		(AffixFilter,		MaxDamage,		AFltMaxDmg,	double,	"the AffixFilter's maximum attack damage."	)
DEFINE_CMD_PAIR		(AffixFilter,		MinReach,		AFltMinRch,	double,	"the AffixFilter's minimum reach."			)
DEFINE_CMD_PAIR		(AffixFilter,		MaxReach,		AFltMaxRch,	double,	"the AffixFilter's maximum reach."			)
DEFINE_CMD_PAIR		(AffixFilter,		MinSpeed,		AFltMinSpd,	double,	"the AffixFilter's minimum attack speed."	)
DEFINE_CMD_PAIR		(AffixFilter,		MaxSpeed,		AFltMaxSpd,	double,	"the AffixFilter's maximum attack speed."	)
DEFINE_CMD_PAIR		(AffixFilter,		IgnoresNormalWeaponResistance,IgnNWRes,	int,"the AffixFilter requires ignoring normal weapon resistance.")
DEFINE_CMD_PAIR_STR	(AffixFilter,		ModelFilterWeapon,		AFltModW,	"the AffixFilter's weapon model filter."	)
DEFINE_CMD_PAIR_STR	(AffixFilter,		IconFilterWeapon,		AFltIcoW,	"the AffixFilter's weapon icon filter."		)

bool Cmd_Enchant_Execute(COMMAND_ARGS) {
	UInt32	* refResult = (UInt32 *)result;
	*refResult = 0;

	TESForm* form = NULL;
	UInt32 level = 0;
	UInt32 LtEq = 1;
	if ( ExtractArgs(PASS_EXTRACT_ARGS, &form, &level, &LtEq) ) {
		TESForm* enchd = g_submoduleInfc->Enchant(form, level, LtEq!=0);
		if ( enchd )
			*refResult = enchd->refID;
	}
	return true;
}
DEFINE_CMD_PLUGIN_ALT(Enchant, Ench, "Enchants the passed armor, clothing, or weapon.", 0, kParams_OneInventoryObject_OneInt_OneOptionalInt)

/*--------------------------------------------------------------------------------------------*/
// command registration
void Register_Commands()
{// called during plugin loading to register new script commands
	_MESSAGE("Registering Commands from opcode base %04X ...", OPCODEBASE);
	g_obseIntfc->SetOpcodeBase(OPCODEBASE); // set opcode base
	g_obseIntfc->RegisterCommand(&kCommandInfo_ListMyForms); // register test command

	REGISTER_CMD_PAIR		(MagicItemGenerator,IsSuffix);
	REGISTER_CMD_PAIR		(MagicItemGenerator,MinUses);
	REGISTER_CMD_PAIR		(MagicItemGenerator,MaxUses);
	REGISTER_CMD_PAIR		(MagicItemGenerator,Rank);
	REGISTER_CMD_PAIR		(MagicItemGenerator,Frequency);
	REGISTER_CMD_PAIR		(MagicItemGenerator,IsAutocalc);
	REGISTER_CMD_GET		(MagicItemGenerator,AffixMask);
	REGISTER_CMD_PAIR_STR	(MagicItemGenerator,AffixSubpetty);
	REGISTER_CMD_PAIR_STR	(MagicItemGenerator,AffixPetty);
	REGISTER_CMD_PAIR_STR	(MagicItemGenerator,AffixLesser);
	REGISTER_CMD_PAIR_STR	(MagicItemGenerator,AffixCommon);
	REGISTER_CMD_PAIR_STR	(MagicItemGenerator,AffixGreater);
	REGISTER_CMD_PAIR_STR	(MagicItemGenerator,AffixGrand);
	REGISTER_CMD_PAIR_STR	(MagicItemGenerator,AffixUltragrand);
	REGISTER_CMD_PAIR_STR	(MagicItemGenerator,AffixNegative);
		
	REGISTER_CMD_PAIR_STR	(AffixFilter,		NameFilter);
	REGISTER_CMD_PAIR		(AffixFilter,		MinValue);
	REGISTER_CMD_PAIR		(AffixFilter,		MaxValue);
	REGISTER_CMD_PAIR		(AffixFilter,		MinWeight);
	REGISTER_CMD_PAIR		(AffixFilter,		MaxWeight);
	REGISTER_CMD_PAIR		(AffixFilter,		MinDurability);
	REGISTER_CMD_PAIR		(AffixFilter,		MaxDurability);

	REGISTER_CMD_PAIR		(AffixFilter,		ApparelMask);
	REGISTER_CMD_PAIR		(AffixFilter,		MinArmorRating);
	REGISTER_CMD_PAIR		(AffixFilter,		MaxArmorRating);
	REGISTER_CMD_PAIR		(AffixFilter,		HidesRings);
	REGISTER_CMD_PAIR		(AffixFilter,		HidesAmulet);
	REGISTER_CMD_PAIR		(AffixFilter,		BipedHead);
	REGISTER_CMD_PAIR		(AffixFilter,		BipedHair);
	REGISTER_CMD_PAIR		(AffixFilter,		BipedBodyLower);
	REGISTER_CMD_PAIR		(AffixFilter,		BipedBodyUpper);
	REGISTER_CMD_PAIR		(AffixFilter,		BipedHand);
	REGISTER_CMD_PAIR		(AffixFilter,		BipedFoot);
	REGISTER_CMD_PAIR		(AffixFilter,		BipedRingLeft);
	REGISTER_CMD_PAIR		(AffixFilter,		BipedRingRight);
	REGISTER_CMD_PAIR		(AffixFilter,		BipedAmulet);
	REGISTER_CMD_PAIR		(AffixFilter,		BipedWeapon);
	REGISTER_CMD_PAIR		(AffixFilter,		BipedWeaponBack);
	REGISTER_CMD_PAIR		(AffixFilter,		BipedWeaponSide);
	REGISTER_CMD_PAIR		(AffixFilter,		BipedQuiver);
	REGISTER_CMD_PAIR		(AffixFilter,		BipedShield);
	REGISTER_CMD_PAIR		(AffixFilter,		BipedTorch);
	REGISTER_CMD_PAIR		(AffixFilter,		BipedTail);
	REGISTER_CMD_PAIR_STR	(AffixFilter,		ModelFilterBipedMale);
	REGISTER_CMD_PAIR_STR	(AffixFilter,		ModelFilterBipedFemale);
	REGISTER_CMD_PAIR_STR	(AffixFilter,		ModelFilterGroundMale);
	REGISTER_CMD_PAIR_STR	(AffixFilter,		ModelFilterGroundFemale);
	REGISTER_CMD_PAIR_STR	(AffixFilter,		IconFilterMale);
	REGISTER_CMD_PAIR_STR	(AffixFilter,		IconFilterFemale);
		
	REGISTER_CMD_PAIR		(AffixFilter,		WeaponMask);
	REGISTER_CMD_PAIR		(AffixFilter,		MinDamage);
	REGISTER_CMD_PAIR		(AffixFilter,		MaxDamage);
	REGISTER_CMD_PAIR		(AffixFilter,		MinReach);
	REGISTER_CMD_PAIR		(AffixFilter,		MaxReach);
	REGISTER_CMD_PAIR		(AffixFilter,		MinSpeed);
	REGISTER_CMD_PAIR		(AffixFilter,		MaxSpeed);
	REGISTER_CMD_PAIR		(AffixFilter,		IgnoresNormalWeaponResistance);
	REGISTER_CMD_PAIR_STR	(AffixFilter,		ModelFilterWeapon);
	REGISTER_CMD_PAIR_STR	(AffixFilter,		IconFilterWeapon);

	REGISTER_CMD_FORM(Enchant);
}

/*--------------------------------------------------------------------------------------------*/
// CSE command parsing
void CSEPrintCallback(const char* message, const char* prefix)
{/*	Called whenever output is provided to CSE console, if present
	Commands recognized by this parser take the form '"COEF_AdvancedExample" commandName [args...]'
*/
	char buffer[0x200];
	strcpy_s(buffer,sizeof(buffer),message);
	char* context = 0;
	if (!message || _stricmp(strtok_s(const_cast<char*>(buffer)," \t",&context),"COEF_AdvancedExample") != 0) return; // output is not a command targeted to this plugin
	const char* command = strtok_s(0," \t",&context);   // extract command name using strtok()
	_DMESSAGE("%s %s %s",prefix,buffer,command);
	if (!command) return;    
	const char* argA = strtok_s(0," \t",&context);  // extract 1st arg, if present
	const char* argB = strtok_s(0," \t",&context);  // extract 2nd arg, if present
	const char* argC = strtok_s(0," \t",&context);  // extract 3rd arg, if present
	if (_stricmp(command,"Description") == 0)    // 'Description' command
	{
		_MESSAGE("%s",g_submoduleInfc->Description());
	}
	else if (_stricmp(command,"ListMyForms") == 0)    // 'ListMyForms' command
	{        
		g_submoduleInfc->ListMyForms();
	}
}
